/*  
 *  Copyright 2006 Paul Jack.
 *
 *  This file is part of the Dex compiler suite. 
 *  
 *  Dex is free software; you can redistribute it and/or modify it
 *  under the terms of the GNU General Public License as published by the
 *  Free Software Foundation; either version 2 of the License, or (at your
 *  option) any later version.
 *  
 *  Dex is distributed in the hope that it will be useful, but
 *  WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
 *  Public License for more details.
 *  
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
 */
package dex.compiler.model.expression;


/**
 * Walks a tree of expression nodes.
 * Subclasses can override specific protected methods if they wish to alter
 * the default traversal.  For instance, an interpreter subclass can override
 * <code>walkInfixExpression</code> to implement a short-circuit traversal
 * for boolean operators.
 */
public abstract class ExpressionWalker implements ExpressionVisitor {


	/**
	 * Constructs a new <code>ExpressionWalker</code>.
	 */
	public ExpressionWalker() {
	}


	/**
	 * Walks the given expression.  One of the protected <code>walk</code>
	 * methods will be invoked based on the specific type of the given
	 * expression.
	 * 
	 * @param expression  the expresson to walk
	 */
	public void walk(Expression expression) {
		if (expression == null) {
			throw new IllegalArgumentException("expression must not be null.");
		}
		if (expression instanceof ArrayExpression) {
			walkArrayExpression((ArrayExpression)expression);
			return;
		}
		if (expression instanceof CastExpression) {
			walkCastExpression((CastExpression)expression);
			return;
		}
		if (expression instanceof DirectCall) {
			walkDirectCall((DirectCall)expression);
			return;
		}
		if (expression instanceof IdentifierExpression) {
			walkIdentifierExpression((IdentifierExpression)expression);
			return;
		}
		if (expression instanceof IndirectCall) {
			walkIndirectCall((IndirectCall)expression);
			return;
		}
		if (expression instanceof InfixExpression) {
			walkInfixExpression((InfixExpression)expression);
			return;
		}
		if (expression instanceof IsExpression) {
			walkIsExpression((IsExpression)expression);
			return;
		}
		if (expression instanceof LiteralBoolean) {
			walkLiteralBoolean((LiteralBoolean)expression);
			return;
		}
		if (expression instanceof LiteralFunction) {
			walkLiteralFunction((LiteralFunction)expression);
			return;
		}
		if (expression instanceof LiteralInteger) {
			walkLiteralInteger((LiteralInteger)expression);
			return;
		}
		if (expression instanceof LiteralString) {
			walkLiteralString((LiteralString)expression);
			return;
		}
		if (expression instanceof MemberExpression) {
			walk((MemberExpression)expression);
			return;
		}
		if (expression instanceof NewExpression) {
			walkNewExpression((NewExpression)expression);
			return;
		}
		if (expression instanceof UnaryExpression) {
			walkUnaryExpression((UnaryExpression)expression);
			return;
		}
		if (expression instanceof VirtualCall) {
			walkVirtualCall((VirtualCall)expression);
			return;
		}
		throw new AssertionError(expression.getClass().getName());
	}


	/**
	 * Walks the given array expression.  The default implementation
	 * first walks the array subexpression, then walks the index
	 * subexpression, and finally visists the given expression.
	 * 
	 * @param expression  the expresson to walk
	 */
	protected void walkArrayExpression(ArrayExpression expression) {
		walk(expression.getArray());
		walk(expression.getIndex());
		this.visitArrayExpression(expression);
	}


	/**
	 * Walks the given cast expression.  The default implementation
	 * walks the value subexpression, then visits the given expression.
	 * 
	 * @param expression  the expresson to walk
	 */
	protected void walkCastExpression(CastExpression expression) {
		walk(expression.getValue());
		this.visitCastExpression(expression);
	}


	/**
	 * Walks the given direct call expression.  The default implementation
	 * walks each parameter subexpression from first to last, then
	 * visits the given expression.
	 * 
	 * @param expression  the expresson to walk
	 */
	protected void walkDirectCall(DirectCall expression) {
		for (Expression e: expression.getParameters()) {
			walk(e);
		}
		this.visitDirectCall(expression);
	}


	/**
	 * Walks the given identifier expression.  The default implementation
	 * just visits the given expression.
	 * 
	 * @param expression  the expresson to walk
	 */
	protected void walkIdentifierExpression(IdentifierExpression expression) {
		this.visitIdentifierExpression(expression);
	}


	/**
	 * Walks the given indirect call expression.  The default implementation
	 * first walks the function subexpression, then walks each parameter
	 * subexpression from first to last, then finally visits the given
	 * expression.
	 * 
	 * @param expression  the expresson to walk
	 */
	protected void walkIndirectCall(IndirectCall expression) {
		walk(expression.getOwner());
		for (Expression e: expression.getParameters()) {
			walk(e);
		}
		this.visitCallExpression(expression);
	}


	/**
	 * Walks the given infix expression.  The default implementation walks
	 * the left subexpression, then the right subexpression, and finally
	 * visits the given expression.
	 * 
	 * @param expression  the expresson to walk
	 */
	protected void walkInfixExpression(InfixExpression expression) {
		walk(expression.getLeft());
		walk(expression.getRight());
		this.visitInfixExpression(expression);
	}


	/**
	 * Walks the given is expression.  The default implementation walks
	 * the value subexpression, then visits the given expression.
	 * 
	 * @param expression  the expresson to walk
	 */
	protected void walkIsExpression(IsExpression expression) {
		walk(expression.getValue());
		this.visitIsExpression(expression);
	}


	/**
	 * Walks the given literal boolean.  The default implementation
	 * just visits the given expression.
	 * 
	 * @param expression  the expresson to walk
	 */
	protected void walkLiteralBoolean(LiteralBoolean expression) {
		this.visitLiteralBoolean(expression);
	}


	/**
	 * Walks the given literal integer.  The default implementation
	 * just visits the given expression.
	 * 
	 * @param expression  the expresson to walk
	 */
	protected void walkLiteralInteger(LiteralInteger expression) {
		this.visitLiteralInteger(expression);
	}


	/**
	 * Walks the given literal function.  The default implementation
	 * just visits the given expression.
	 * 
	 * @param expression  the expresson to walk
	 */
	protected void walkLiteralFunction(LiteralFunction expression) {
		this.visitLiteralFunction(expression);
	}


	/**
	 * Walks the given literal string.  The default implementation
	 * just visits the given expression.
	 * 
	 * @param expression  the expresson to walk
	 */
	protected void walkLiteralString(LiteralString expression) {
		this.visitLiteralString(expression);
	}


	/**
	 * Walks the given member expression.  The default implementation
	 * first walks the owner subexpression, then visits the given
	 * expression.
	 * 
	 * @param expression  the expresson to walk
	 */
	protected void walk(MemberExpression expression) {
		walk(expression.getOwner());
		this.visitMemberExpression(expression);
	}


	/**
	 * Walks the given new expression.  The default implementation
	 * first walks the parameter subexpressions from first to last,
	 * then visits the given expression.
	 * 
	 * @param expression  the expresson to walk
	 */
	protected void walkNewExpression(NewExpression expression) {
		for (Expression e: expression.getParameters()) {
			walk(e);
		}
		this.visitNewExpression(expression);
	}


	/**
	 * Walks the given unary expression.  The default implementation
	 * first walks the operand subexpression, then visits the 
	 * given expression.
	 * 
	 * @param expression  the expresson to walk
	 */
	protected void walkUnaryExpression(UnaryExpression expression) {
		walk(expression.getOperand());
		this.visitUnaryExpression(expression);
	}


	/**
	 * Walks the given virtual call expression.
	 * 
	 * @param expression  the expresson to walk
	 */
	protected void walkVirtualCall(VirtualCall expression) {
		walk(expression.getObject());
		for (Expression e: expression.getParameters()) {
			walk(e);
		}
		this.visitVirtualCall(expression);
	}


}
